package com.ideal.manage.esms.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ideal.manage.esms.bean.project.EquipmentInfo;
import com.ideal.manage.esms.bean.project.EquipmentManage;
import com.ideal.manage.esms.bean.project.ParameterInfo;
import com.ideal.manage.esms.bean.project.ProjectManage;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram;
import org.elasticsearch.search.aggregations.metrics.avg.Avg;
import org.elasticsearch.search.aggregations.metrics.max.Max;
import org.elasticsearch.search.aggregations.metrics.min.Min;
import org.elasticsearch.search.aggregations.metrics.stats.Stats;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Created By Dai On 2018/5/15
 * Remark: Elasticsearch的工具类
 *
 * @author Dai
 */
@Component
public class ElasticsearchUtils {
    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchUtils.class);
    public final static String GLOBAL_TYPE = "mdbs_type";

    @Autowired
    private TransportClient transportClient;

    private static TransportClient client;


    @PostConstruct
    public void init() {
        client = this.transportClient;
    }

    public static void createIndex(String index, String type) {
        CreateIndexRequestBuilder cib = client.admin()
                .indices().prepareCreate(index);
        XContentBuilder mapping = null;
        try {
            mapping = XContentFactory.jsonBuilder()
                    .startObject()
                    .field("dynamic", "true")
                    //设置自定义字段
                    .startObject("properties")
                    .startObject("time")
                    //设置Date类型
                    .field("type", "date")
                    //设置Date的格式
                    .field("format", "epoch_millis||yyyy-MM-dd HH:mm:ss")
                    .endObject()
                    .endObject()
                    .endObject();
        } catch (IOException e) {
            e.printStackTrace();
        }
        cib.addMapping(type, mapping);
        cib.execute().actionGet();
    }

    public static void ensureIndex(String index, String type) {
        IndicesExistsRequest request = new IndicesExistsRequest(index);
        IndicesExistsResponse response = client.admin().indices().exists(request).actionGet();
        if (!response.isExists()) {
            ElasticsearchUtils.createIndex(index, type);
        }
    }

    /**
     * 批量插入
     *
     * @param jsondataList
     * @return
     */
    public static BulkResponse bulk(String index, String type, JSONArray jsondataList) {
        BulkRequestBuilder bulkRequest = client.prepareBulk();
        for (int i = 0, j = jsondataList.size(); i < j; i++) {
            String jsondata = jsondataList.get(i).toString();
            logger.info("jsondata -------> " + jsondata);
            bulkRequest.add(client.prepareIndex(index, type).setSource(jsondata, XContentType.JSON));
        }
        return bulkRequest.execute().actionGet();
    }

//    --------------------------------------------------------- 数 据 列 表 ---------------------------------------------------------

    /**
     * 获取累计值 并返回整个List
     *
     * @param list 参数list
     * @return
     */
    public static List<ParameterInfo> getSumValue(List<ParameterInfo> list, EquipmentManage equipmentManage) {
        // 过滤电池单体中唯一标识
        String code = equipmentManage.getCode();

        // 这里是获取设备唯一的标识
        String macid = code.indexOf("#") < 0 ? code : code.substring(0, code.indexOf("#"));


        // 获取电池单体的esName(需要拼接)
        String battery = code.substring(code.indexOf("#") + 1, code.length());
        // ---------------------------------过滤完成------------------------------END
        // 累计询问过后是累计这个月的值
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Long time = calendar.getTimeInMillis();
        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        prepareSearch.setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", macid))
                        .must(QueryBuilders.rangeQuery("time").lte(time))
        );
        logger.info("getSumValue -------> " + prepareSearch.toString());
        // 2. 找到所有需要查询的字段(不能重复)
        Set<String> fields = new HashSet<>();
        list.forEach(parameterInfo -> {
            fields.add(battery + parameterInfo.getEsName());
        });
        // 3. 设置一下查询条件
        fields.forEach(string -> {
            prepareSearch.addAggregation(AggregationBuilders.sum("sum_" + string).field(string));
        });
        // 4. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        // 5. 塞进去
        list.forEach(parameterInfo -> {
            Sum agg = searchResponse.getAggregations().get("sum_" + battery + parameterInfo.getEsName());
            double value = agg.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            parameterInfo.setValue(value);
        });
        return list;
    }

    /**
     * 获取累计值 并返回整个List
     *
     * @param list 参数list
     * @return
     */
    public static List<ParameterInfo> getSumValue(List<ParameterInfo> list, ProjectManage projectManage) {
        // 累计询问过后是累计这个月的值
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Long time = calendar.getTimeInMillis();

        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("ip", projectManage.getIp()))
                .must(QueryBuilders.rangeQuery("time").lte(time));
        for (ParameterInfo parameterInfo : list) {
            String field = parameterInfo.getEsName();
            queryBuilder.must(QueryBuilders.existsQuery(parameterInfo.getEsName()));
        }
        prepareSearch.setQuery(
                queryBuilder
        );
        logger.info("getSumValue -------> " + prepareSearch.toString());
        // 2. 找到所有需要查询的字段(不能重复)
        Set<String> fields = new HashSet<>();
        list.forEach(parameterInfo -> {
            fields.add(parameterInfo.getEsName());
        });
        // 3. 设置一下查询条件
        fields.forEach(string -> {
            prepareSearch.addAggregation(AggregationBuilders.sum("sum_" + string).field(string));
        });
        // 4. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        // 5. 塞进去
        list.forEach(parameterInfo -> {
            Sum agg = searchResponse.getAggregations().get("sum_" + parameterInfo.getEsName());
            double value = agg.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            parameterInfo.setValue(value);
        });
        return list;
    }

    /**
     * 获取今日的值 并返回整个List
     *
     * @param list 参数list
     * @return
     */
    public static List<ParameterInfo> getTodayValue(List<ParameterInfo> list, EquipmentManage equipmentManage) {
        // 过滤电池单体中唯一标识
        String code = equipmentManage.getCode();

        // 这里是获取设备唯一的标识
        String macid = code.indexOf("#") < 0 ? code : code.substring(0, code.indexOf("#"));


        // 获取电池单体的esName(需要拼接)
        String battery = code.substring(code.indexOf("#") + 1, code.length());
        // ---------------------------------过滤完成------------------------------END

        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 因为是今天的，所以要加上查询语句
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        // 获取今天00:00:00.000的时间
        Long time = calendar.getTimeInMillis();
        prepareSearch.setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", macid))
                        .must(QueryBuilders.rangeQuery("time").gte(time))
        );
        logger.info("getTodayValue -------> " + prepareSearch.toString());
        // 3. 找到所有需要查询的字段(不能重复)
        Set<String> fields = new HashSet<>();
        list.forEach(parameterInfo -> {
            fields.add(battery + parameterInfo.getEsName());
        });
        // 4. 设置一下查询条件
        fields.forEach(string -> {
            prepareSearch.addAggregation(AggregationBuilders.stats("stats_" + string).field(string));
        });
        System.out.println(prepareSearch.toString());

        // 5. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        // 6. 塞进去
        for (ParameterInfo parameterInfo : list) {
            Stats agg = searchResponse.getAggregations().get("stats_" + battery + parameterInfo.getEsName());
            double value = 0.0;
            String method = parameterInfo.getEsAggsMethod().toString();
            //今日累计
            if ("2".equals(method)) {
                value = agg.getSum();
                // 最高
            } else if ("4".equals(method)) {
                value = agg.getMax();
                // 最低
            } else if ("5".equals(method)) {
                value = agg.getMin();
                // 极差
            } else if ("6".equals(method)) {
                value = agg.getMax() - agg.getMin();
                // 平均
            } else if ("7".equals(method)) {
                value = agg.getAvg();
            }
            // 7. 如果值是无限大 或者 NaN时 做个处理
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            parameterInfo.setValue(value);
        }
        return list;
    }

    /**
     * 获取今日的值 并返回整个List
     *
     * @param list 参数list
     * @return
     */
    public static List<ParameterInfo> getTodayValue(List<ParameterInfo> list, ProjectManage projectManage) {
        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 因为是今天的，所以要加上查询语句
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        // 获取今天00:00:00.000的时间
        Long time = calendar.getTimeInMillis();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("ip", projectManage.getIp()))
                .must(QueryBuilders.rangeQuery("time").lte(time));
        for (ParameterInfo parameterInfo : list) {

            queryBuilder.must(QueryBuilders.existsQuery(parameterInfo.getEsName()));
        }
        prepareSearch.setQuery(
                queryBuilder
        );
        logger.info("getTodayValue -------> " + prepareSearch.toString());
        // 3. 找到所有需要查询的字段(不能重复)
        Set<String> fields = new HashSet<>();
        list.forEach(parameterInfo -> {
            fields.add(parameterInfo.getEsName());
        });
        // 4. 设置一下查询条件
        fields.forEach(string -> {
            prepareSearch.addAggregation(AggregationBuilders.stats("stats_" + string).field(string));
        });
        // 5. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        // 6. 塞进去
        list.forEach(parameterInfo -> {
            Stats agg = searchResponse.getAggregations().get("stats_" + parameterInfo.getEsName());
            double value = 0.0;
            String method = parameterInfo.getEsAggsMethod().toString();
            if ("2".equals(method)) {  //今日累计
                value = agg.getSum();
            } else if ("4".equals(method)) {   // 最高
                value = agg.getMax();
            } else if ("5".equals(method)) {   // 最低
                value = agg.getMin();
            } else if ("6".equals(method)) {   // 极差
                value = agg.getMax() - agg.getMin();
            } else if ("7".equals(method)) {   // 平均
                value = agg.getAvg();
            }
            // 7. 如果值是无限大 或者 NaN时 做个处理
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            parameterInfo.setValue(value);
        });
        return list;
    }

    /**
     * 获取实时数据（其实是1分钟之前的 因为好像数据同步了时间没同步- -）
     *
     * @param list 参数list
     * @return
     */
    public static List<ParameterInfo> getNowValue(List<ParameterInfo> list, EquipmentManage equipmentManage) {
        // 过滤电池单体中唯一标识
        String code = equipmentManage.getCode();

        // 这里是获取设备唯一的标识
        String macid = code.indexOf("#") < 0 ? code : code.substring(0, code.indexOf("#"));


        // 获取电池单体的esName(需要拼接)
        String battery = code.substring(code.indexOf("#") + 1, code.length());
        // ---------------------------------过滤完成------------------------------END

        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 设置查询语句
        prepareSearch.setSize(1000).setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", macid))
                        .must(QueryBuilders.rangeQuery("time").gte(System.currentTimeMillis() - 15000))

        );
        // 3. 添加去重
        //prepareSearch.setCollapse(new CollapseBuilder("macid.keyword")).addSort(SortBuilders.fieldSort("time"));
        logger.info("getNowValue -------> " + prepareSearch.toString());
        // 3. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit[] hits = searchResponse.getHits().getHits();
        if (hits.length < 1) {
            list.forEach(parameterInfo -> {
                parameterInfo.setValue(null);
            });
            return list;
        }
        // SearchHit hit = hits[0];
        Map<String, Object> map = new HashMap<>();
        for (SearchHit hit : hits) {
            map.putAll(hit.getSourceAsMap());
        }


        // 通过比较获取相应的值
        for (ParameterInfo parameterInfo : list) {
            Object o;
            if (map.containsKey(parameterInfo.getEsName())) {
                o = map.get(parameterInfo.getEsName());
                map.remove(parameterInfo.getEsName());
            } else {
                o = map.get(battery + parameterInfo.getEsName());
            }
            String s;
            if (o == null) {
                s = "0.00";
            } else {
                s = o.toString();
            }
            Double value = Double.parseDouble(s);
            parameterInfo.setValue(value);
        }

        return list;
    }

    /**
     * 获取实时数据（其实是1分钟之前的 因为好像数据同步了时间没同步- -）
     *
     * @param list 参数list
     * @return
     */
    public static List<ParameterInfo> getNowValue(List<ParameterInfo> list, ProjectManage projectManage) {

        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 设置查询语句
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("ip", projectManage.getIp()))
                .must(QueryBuilders.rangeQuery("time").gte(System.currentTimeMillis() - 4000));

        for (ParameterInfo parameterInfo : list) {
            String field = parameterInfo.getEsName();
            queryBuilder.must(QueryBuilders.existsQuery(parameterInfo.getEsName()));
        }
        prepareSearch.setQuery(
                queryBuilder
        );
        // 3. 添加去重
        prepareSearch.setCollapse(new CollapseBuilder("macid.keyword")).addSort(SortBuilders.fieldSort("time"));
        logger.info("getNowValue -------> " + prepareSearch.toString());
        // 3. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit[] hits = searchResponse.getHits().getHits();
        if (hits.length < 1) {
            list.forEach(parameterInfo -> {
                parameterInfo.setValue(null);
            });
            return list;
        }
        SearchHit hit = hits[0];
        Map<String, Object> map = hit.getSourceAsMap();
        // 4. 塞进去
        for (ParameterInfo parameterInfo : list) {
            Object o = map.get(parameterInfo.getEsName());
            String s;
            if (o == null) {
                s = "0.00";
            } else {
                s = o.toString();
            }
            Double value = Double.parseDouble(s);
            parameterInfo.setValue(value);
        }
        ;
        return list;
    }

    /**
     * 获取设备状态的实时数据（其实是1分钟之前的 因为好像数据同步了时间没同步- -）
     *
     * @param list 参数list
     * @return
     */
    public static List<EquipmentInfo> getEquipmentInfoNowValue(List<EquipmentInfo> list, EquipmentManage equipmentManage) {
        // 1. 查询用的API
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 设置查询语句
        prepareSearch.setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", equipmentManage.getCode()))
                        .must(QueryBuilders.rangeQuery("time").lt(System.currentTimeMillis() - 60000))
        );
        // 3. 添加去重
        prepareSearch.setCollapse(new CollapseBuilder("macid.keyword")).addSort(SortBuilders.fieldSort("time"));
        logger.info("getNowValue -------> " + prepareSearch.toString());
        // 3. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit[] hits = searchResponse.getHits().getHits();
        if (hits.length < 1) {
            list.forEach(equipmentInfo -> {
                equipmentInfo.setValue(null);
            });
            return list;
        }
        SearchHit hit = hits[0];
        Map<String, Object> map = hit.getSourceAsMap();
        // 4. 塞进去
        String s = "";
        for (EquipmentInfo equipmentInfo : list) {

            Object o = map.get(equipmentInfo.getEsName());
            if (o != null) {
                s = o.toString();
            }
            s = (o == null ? "0" : s);
            Integer value = Integer.parseInt(s);
            equipmentInfo.setValue(value);
        }
        ;
        return list;
    }

    /**
     * 获取设备状态的实时数据
     *
     * @param list 参数list
     * @return
     */
    public static List<EquipmentManage> getEquipmentManageNowValue(List<EquipmentManage> list, ProjectManage projectManage) {
        //处理code 和 esName
        String macid = list.get(0).getCode().substring(0, list.get(0).getCode().indexOf("#"));
        List<String> batteryGroup = new ArrayList();
        for (int i = 0; i < list.size(); i++) {
            batteryGroup.add(list.get(i).getCode().substring(list.get(i).getCode().indexOf("#") + 1, list.get(i).getCode().length()) + "Volt");
        }


        for (int i = 0; i < batteryGroup.size(); i++) {
            // 1. 查询用的API
            SearchRequestBuilder prepareSearch = client.prepareSearch();
            // 2. 设置查询语句
            prepareSearch.setQuery(
                    QueryBuilders.boolQuery()
                            .must(QueryBuilders.termQuery("ip", projectManage.getIp()))
                            .must(QueryBuilders.termsQuery("macid", macid))
                            .must(QueryBuilders.existsQuery(batteryGroup.get(i)))
                            .must(QueryBuilders.rangeQuery("time").gte(System.currentTimeMillis() - 15000))
            );
            // 3. 添加去重
            //prepareSearch.setCollapse(new CollapseBuilder(batteryGroup.get(i)+".keyword")).addSort(SortBuilders.fieldSort("time"));
            logger.info("电池单体" + i + " -------> " + prepareSearch.toString());

            // 3. 获取查询结果
            SearchResponse searchResponse = prepareSearch.execute().actionGet();
            SearchHit[] hits = searchResponse.getHits().getHits();
            if (hits.length < 1) {
                list.forEach(manage -> {
                    manage.setBatteryAndTemp(null);
                });
                return list;
            }
            // 4. 塞进去
            String s = "";
            String s1 = "";
            for (EquipmentManage manage : list) {
                for (int t = 0; t < hits.length; i++) {
                    SearchHit hit = hits[t];
                    Map<String, Object> map = hit.getSourceAsMap();
                    if (macid.equals(map.get("macid"))) {
                        Object voltage = map.get(batteryGroup.get(i));

                        if (voltage != null) {
                            s = voltage.toString();
                        }

                        s = (voltage == null ? "0" : s);

                        Double s_vol = Double.parseDouble(s) * 0.001D;

                        DecimalFormat df = new DecimalFormat("0.00");
                        //6.20   这个是字符串，但已经是我要的两位小数了
                        String vol = df.format(s_vol);


                        manage.setVol(Double.parseDouble(vol));

                    }
                    break;
                }

            }
        }
        return list;
    }

//    --------------------------------------------------------- 列 表 最 大 最 小 ---------------------------------------------------------

    /**
     * 根据 电池单体列表 排序找到实时情况下的top 和 bottom 值
     *
     * @param batteryList 电池单体列表
     * @param field       排序、取值的key
     * @param size        显示多少个
     * @return
     */
    public static List getTopAndLowValue(List<EquipmentManage> batteryList, String field, String ip, int size) {
        logger.info("getTopAndLowValue -----> getSearchResponse");
        // 1. 获取时间，因为需要实时的，所以取4秒以前的时间，获取离现在最近的数据
        Long time = System.currentTimeMillis() - 3000;
        // 2. 获取结果
        SearchResponse searchResponseDESC = getSearchResponse(batteryList, field, ip, size, "DESC", time);
        SearchResponse searchResponseASC = getSearchResponse(batteryList, field, ip, size, "ASC", time);
        // 3. 解析结果
        List list = new ArrayList();
        JSONObject jsonObject;
        SearchHit[] hitsDESC = searchResponseDESC.getHits().getHits();  // 最大的
        SearchHit[] hitsASC = searchResponseASC.getHits().getHits();    // 最小的
        if (hitsASC.length < 1 || hitsDESC.length < 1) {
            return list;
        }
        for (int i = 0; i < size; i++) {
            jsonObject = new JSONObject();
            double top_value = Double.parseDouble(hitsDESC[i].getSortValues()[1].toString());
            double bottom_value = Double.parseDouble(hitsASC[i].getSortValues()[1].toString());
            String top_code = hitsDESC[i].getFields().get("macid.keyword").getValue().toString();
            String bottom_code = hitsASC[i].getFields().get("macid.keyword").getValue().toString();
            String top_name = "";
            String bottom_name = "";
            for (EquipmentManage equipmentManage : batteryList) {
                String code = equipmentManage.getCode();
                if (top_code.equals(code)) {
                    top_name = equipmentManage.getName();
                }
                if (bottom_code.equals(code)) {
                    bottom_name = equipmentManage.getName();
                }
            }
            jsonObject.put("top_value", top_value);
            jsonObject.put("top_name", top_name);
            jsonObject.put("bottom_value", bottom_value);
            jsonObject.put("bottom_name", bottom_name);
            list.add(jsonObject);
        }
        return list;
    }

    /**
     * 返回一个对象 包括最大和最小的数据
     *
     * @param batteryList 电池单体列表
     * @param field       字段
     * @param ip          ip
     * @param size        显示多少个
     * @return
     */
    public static JSONObject getTopAndBottom(List<EquipmentManage> batteryList, String field, String ip, int size) {
        logger.info("getTopAndBottom -----> getSearchResponse");
        // 1. 获取时间，因为需要实时的，所以取4秒以前的时间，获取离现在最近的数据
        Long time = System.currentTimeMillis() - 3000;
        // 2. 要返回的对象
        JSONObject jsonObject = new JSONObject();
        // 3. 获取结果
        SearchResponse searchResponseDESC = getSearchResponse(batteryList, field, ip, 5, "DESC", time);
        SearchResponse searchResponseASC = getSearchResponse(batteryList, field, ip, 5, "ASC", time);
        // 4. 解析结果
        jsonObject = addValueToJSONObject(searchResponseDESC, jsonObject, batteryList);
        jsonObject = addValueToJSONObject(searchResponseASC, jsonObject, batteryList);
        return jsonObject;
    }

    /**
     * 返回一个对象 包括最大和最小的数据
     *
     * @param batteryList 电池单体列表
     * @param field       字段
     * @param ip          ip
     * @return
     */
    public static JSONObject packageInfo(List<EquipmentManage> batteryList, String field, String ip, String
            sort, String equipmentType) {
        logger.info("packageInfo -----> getSearchResponse");
        // 1. 要返回的对象
        JSONObject jsonObject = new JSONObject();
        // 2. 获取时间，因为需要实时的，所以取4秒以前的时间，获取离现在最近的数据
        Long time = System.currentTimeMillis() - 3000;
        // 3. 获取返回值
        SearchResponse searchResponse = getSearchResponse(batteryList, field, ip, batteryList.size(), sort, time);
        // 4. 获取结果
        SearchHit[] hits = searchResponse.getHits().getHits();
        // 5. 解析结果
        if (equipmentType.equals("1")) {
            for (int i = 0; i < hits.length; i++) {
                double value = Double.parseDouble(hits[i].getSortValues()[1].toString());
                String code = hits[i].getFields().get("macid.keyword").getValue().toString();
                String name = "";
                for (EquipmentManage equipmentManage : batteryList) {
                    if (code.equals(equipmentManage.getCode())) {
                        name = equipmentManage.getParent().getName();
                        break;
                    }
                }
                if (jsonObject.get(name) == null) {
                    jsonObject.put(name, value);
                }
            }
        } else {
            for (int i = 0; i < hits.length; i++) {
                double value = Double.parseDouble(hits[i].getSortValues()[1].toString());
                String code = hits[i].getFields().get("macid.keyword").getValue().toString();
                String name = "";
                for (EquipmentManage equipmentManage : batteryList) {
                    if (code.equals(equipmentManage.getCode())) {
                        name = equipmentManage.getParent().getParent().getName();
                        break;
                    }
                }
                if (jsonObject.get(name) == null) {
                    jsonObject.put(name, value);
                }
            }
        }

        return jsonObject;
    }

    /**
     * 根据 排序 获取 最大最小值 的通用方法
     *
     * @param batteryList 电池单体列表
     * @param field       字段
     * @param ip          ip
     * @param size        显示多少个
     * @param sort        排序 "ASC"/"DESC"
     * @return
     */
    private static SearchResponse getSearchResponse(List<EquipmentManage> batteryList,
                                                    String field, String ip, Integer size,
                                                    String sort, Long time) {
        // 1. 准备查询语句
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 获取所有的设备的id
        Set<String> strings = new HashSet<>();
        batteryList.forEach(battery -> {
            if (StringUtils.isNotBlank(battery.getCode())) {
                strings.add(battery.getCode());
            }
        });
        // 4. 判断是asc 还是 desc
        SortBuilder sortBuilder;
        if ("ASC".equals(sort)) {
            sortBuilder = SortBuilders.fieldSort(field).order(SortOrder.ASC);
        } else if ("DESC".equals(sort)) {
            sortBuilder = SortBuilders.fieldSort(field).order(SortOrder.DESC);
        } else {
            return null;
        }
        // 4. 设置过滤条件
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("macid", strings))
                .must(QueryBuilders.termQuery("ip", ip))
                .must(QueryBuilders.rangeQuery("time").gte(time))
        )
                .addSort(SortBuilders.fieldSort("time").order(SortOrder.DESC))
                .addSort(sortBuilder)
                .setSize(size)
                .setCollapse(new CollapseBuilder("macid.keyword"));
        logger.info("getSearchResponse -----> " + prepareSearch.toString());
        // 5. 获取结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        return searchResponse;
    }

    /**
     * 把数值加入JSONObject
     *
     * @param searchResponse
     * @param jsonObject
     * @param batteryList    电池单体列表
     * @return
     */
    private static JSONObject addValueToJSONObject(SearchResponse searchResponse, JSONObject
            jsonObject, List<EquipmentManage> batteryList) {
        // 1. 获取所有的 hits
        SearchHit[] hits = searchResponse.getHits().getHits();
        // 2. 解析
        for (int i = 0; i < hits.length; i++) {
            double value = Double.parseDouble(hits[i].getSortValues()[1].toString());
            String code = hits[i].getFields().get("macid.keyword").getValue().toString();
            String name = "";
            for (EquipmentManage equipmentManage : batteryList) {
                if (equipmentManage.getCode().equals(code)) {
                    name = equipmentManage.getName();
                    break;
                }
            }
            jsonObject.put(name, value);
        }
        return jsonObject;
    }

//    --------------------------------------------------------- 时 间 桶 ---------------------------------------------------------

    /**
     * 这个是一个特殊的方法，分成两部分聚合
     * 1. 取出15分钟里面时间最接近15分的时间，即time取min值
     * 2. 根据时间、ip、macid取出对应的field的值
     *
     * @param code      设备唯一标识
     * @param field     字段
     * @param ip        项目ip
     * @param freque    时间间隔
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static JSONObject getDateHistogramNow(String code, String field, String ip, String freque, Long
            startTime, Long endTime) {

//       1. 取出15分钟里面时间最接近15分的时间，即time取min值
        JSONObject jsonObject = new JSONObject();
        // 1) 准备连接
        SearchRequestBuilder prepareSaerch = client.prepareSearch();
        // 2) 获取最小值的时间需要准备的query
        if ("".equals(code)) {
            prepareSaerch.setQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("ip", ip))
                    .must(QueryBuilders.rangeQuery("time").gte(startTime).lte(endTime))
                    .must(QueryBuilders.existsQuery(field))
            );
        } else {
            prepareSaerch.setQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("macid", code))
                    .must(QueryBuilders.termQuery("ip", ip))
                    .must(QueryBuilders.rangeQuery("time").gte(startTime).lte(endTime))
                    .must(QueryBuilders.existsQuery(field))
            );
        }

        // 3) 获取间隔 freque
        int freque_int = Integer.parseInt(freque);
        // 4) 设置聚合取接近每个15分钟的最小的时间
        prepareSaerch.addAggregation(
                AggregationBuilders.dateHistogram("get_time_histogram")
                        .field("time")
                        .dateHistogramInterval(DateHistogramInterval.minutes(freque_int))
                        .timeZone(DateTimeZone.forID("+08:00"))
                        .subAggregation(AggregationBuilders.min("get_min_time").field("time"))
        );
        logger.info("getDateHistogramNow -----> " + prepareSaerch.toString());
        SearchResponse searchResponse = prepareSaerch.execute().actionGet();
        // 5) 获取时间的集合
        List<Double> times = new ArrayList<>();
        InternalDateHistogram internalDateHistogram = searchResponse.getAggregations().get("get_time_histogram");
        List<InternalDateHistogram.Bucket> buckets = internalDateHistogram.getBuckets();
        for (InternalDateHistogram.Bucket bucket : buckets) {
            Min min = bucket.getAggregations().get("get_min_time");
            double value = min.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                continue;
            }
            times.add(value);
        }
//        2. 根据时间、ip、macid取出对应的field的值
        // 1) 准备连接
        prepareSaerch = client.prepareSearch();
        // 2) 设置query语句
        if ("".equals(code)) {
            prepareSaerch.setQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("ip", ip))
                    .must(QueryBuilders.termsQuery("time", times))
            );
        } else {
            prepareSaerch.setQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("macid", code))
                    .must(QueryBuilders.termQuery("ip", ip))
                    .must(QueryBuilders.termsQuery("time", times))
            );
        }

        logger.info("getDateHistogramNow -----> " + prepareSaerch.toString());
        // 3) 获取结果
        searchResponse = prepareSaerch.execute().actionGet();
        // 4) 解析结果
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            Map map = hit.getSourceAsMap();
            Object timeObject = map.get("time");
            Object valueObject = map.get(field);
            String time;
            Double value;
            if (timeObject != null) {
                Long timevalue = Long.parseLong(timeObject.toString());
                Date date = new Date(timevalue);
                time = simpleDateFormat.format(date);
            } else {
                continue;
            }
            if (valueObject != null) {
                value = Double.parseDouble(valueObject.toString());
            } else {
                continue;
            }
            jsonObject.put(time, value);
        }
        return jsonObject;
    }

    /**
     * 根据 设备 字段 ip 时间类型等 返回JSONObject
     *
     * @param code      设备唯一标识
     * @param field     字段
     * @param ip        项目ip
     * @param time_type 查询时间类型
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 一个类似于 {"00:00": 5678.90, "01:00": 1234.56, ....} 这样的一个JSONObject
     */
    public static JSONObject getDateHistogramSum(String code,
                                                 String field, String ip, String time_type,
                                                 Long startTime, Long endTime) {
        logger.info("getDateHistogramSum -----> getListInternalDateHistogramBucket");
        JSONObject jsonObject = new JSONObject();
        // 6. 解析结果
        List<InternalDateHistogram.Bucket> buckets = getListInternalDateHistogramBucket(code, field, ip, time_type, startTime, endTime, "sum");
        // 7. 塞进去
        for (InternalDateHistogram.Bucket bucket : buckets) {
            String name = bucket.getKeyAsString();
            Sum sum = bucket.getAggregations().get("sum_value");
            double value = sum.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            jsonObject.put(name, value);
        }
        buckets.forEach(bucket -> {
            String name = bucket.getKeyAsString();
            Sum sum = bucket.getAggregations().get("sum_value");
            double value = sum.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            jsonObject.put(name, value);
        });
        return jsonObject;
    }

    /**
     * 根据 设备 字段 ip 时间类型等 返回JSONObject
     *
     * @param code      设备唯一标识
     * @param field     字段
     * @param ip        项目ip
     * @param time_type 查询时间类型
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 一个类似于 {"00:00": 5678.90, "01:00": 1234.56, ....} 这样的一个JSONObject
     */
    public static JSONObject getDateHistogramAvg(String code,
                                                 String field, String ip, String time_type,
                                                 Long startTime, Long endTime) {
        logger.info("getDateHistogramAvg -----> getListInternalDateHistogramBucket");
        JSONObject jsonObject = new JSONObject();
        // 6. 解析结果
        List<InternalDateHistogram.Bucket> buckets = getListInternalDateHistogramBucket(code, field, ip, time_type, startTime, endTime, "avg");

//        String keyAsString = buckets.get(0).getKeyAsString();
//        System.out.println(keyAsString);

        // 7. 塞进去
        buckets.forEach(bucket -> {
            String name = bucket.getKeyAsString();
            Avg avg = bucket.getAggregations().get("avg_value");
            double value = avg.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            jsonObject.put(name, value);
        });
        return jsonObject;
    }

    /**
     * 根据 设备 字段 ip 时间类型等 返回JSONObject
     *
     * @param code      设备唯一标识
     * @param field     字段
     * @param ip        项目ip
     * @param time_type 查询时间类型
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 一个类似于 {"00:00": 5678.90, "01:00": 1234.56, ....} 这样的一个JSONObject
     */
    public static JSONObject getDateHistogramMin(String code,
                                                 String field, String ip, String time_type,
                                                 Long startTime, Long endTime) {
        logger.info("getDateHistogramMin -----> getListInternalDateHistogramBucket");
        JSONObject jsonObject = new JSONObject();
        // 6. 解析结果
        List<InternalDateHistogram.Bucket> buckets = getListInternalDateHistogramBucket(code, field, ip, time_type, startTime, endTime, "difference");
        // 7. 塞进去
        buckets.forEach(bucket -> {
            String name = bucket.getKeyAsString();
            Min min = bucket.getAggregations().get("min_value");
            double value = min.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            jsonObject.put(name, value);
        });
        return jsonObject;
    }

    /**
     * 根据 设备 字段 ip 时间类型等 返回JSONObject
     *
     * @param code      设备唯一标识
     * @param field     字段
     * @param ip        项目ip
     * @param time_type 查询时间类型
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 一个类似于 {"00:00": 5678.90, "01:00": 1234.56, ....} 这样的一个JSONObject
     */
    public static JSONObject getDateHistogramMax(String code,
                                                 String field, String ip, String time_type,
                                                 Long startTime, Long endTime) {
        logger.info("getDateHistogramMin -----> getListInternalDateHistogramBucket");
        JSONObject jsonObject = new JSONObject();
        // 6. 解析结果
        List<InternalDateHistogram.Bucket> buckets = getListInternalDateHistogramBucket(code, field, ip, time_type, startTime, endTime, "difference");
        // 7. 塞进去
        buckets.forEach(bucket -> {
            String name = bucket.getKeyAsString();
            Max max = bucket.getAggregations().get("max_value");
            double value = max.getValue();
            if (Double.isInfinite(value) || Double.isNaN(value)) {
                value = 0;
            }
            jsonObject.put(name, value);
        });
        return jsonObject;
    }

    /**
     * 根据 设备 字段 ip 时间类型等 返回JSONObject
     *
     * @param code      设备唯一标识
     * @param field     字段
     * @param ip        项目ip
     * @param time_type 查询时间类型
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 一个类似于 {"00:00": 5678.90, "01:00": 1234.56, ....} 这样的一个JSONObject
     */
    public static JSONObject getDateHistogramDifference(String code,
                                                        String field, String ip, String time_type,
                                                        Long startTime, Long endTime) {
        logger.info("getDateHistogramDifference -----> getListInternalDateHistogramBucket");
        JSONObject jsonObject = new JSONObject();
        // 6. 解析结果
        List<InternalDateHistogram.Bucket> buckets = getListInternalDateHistogramBucket(code, field, ip, time_type, startTime, endTime, "difference");
        // 7. 塞进去
        buckets.forEach(bucket -> {
            String name = bucket.getKeyAsString();
            Min min = bucket.getAggregations().get("min_value");
            Max max = bucket.getAggregations().get("max_value");
            double min_value = min.getValue();
            if (Double.isInfinite(min_value) || Double.isNaN(min_value)) {
                min_value = 0;
            }
            double max_value = max.getValue();
            if (Double.isInfinite(max_value) || Double.isNaN(max_value)) {
                max_value = 0;
            }
            double value = max_value - min_value;
            jsonObject.put(name, value);
        });
        return jsonObject;
    }

    /**
     * 这个是上面3个方法的通用结果获取方法
     *
     * @param code       设备唯一标识
     * @param field      字段
     * @param ip         项目ip
     * @param time_type  查询时间类型
     * @param startTime  开始时间
     * @param endTime    结束时间
     * @param value_type 要求的结果类型 sum min max difference
     * @return
     */
    private static List<InternalDateHistogram.Bucket> getListInternalDateHistogramBucket(String code,
                                                                                         String field, String ip, String time_type,
                                                                                         Long startTime, Long endTime, String value_type) {

        if (StringUtils.isEmpty(code)) {
            return new ArrayList<>();
        }
        // 获取macid
        String macid = code.substring(0, code.indexOf("#"));
        // 获取esName
        String esName = code.substring(code.indexOf("#") + 1, code.length());
        String fileds;
        if (field.equals("BatCurrent")) {
            fileds = field;
        } else {
            // 组合filed
            fileds = esName + field;
        }
        // 1. 准备查询语句
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 2. 设置过滤条件
        if ("".equals(macid)) {
            prepareSearch.setQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("ip", ip))
                    .must(QueryBuilders.rangeQuery("time").gte(startTime).lte(endTime))
            );
        } else {
            prepareSearch.setQuery(QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("macid", macid))
                    .must(QueryBuilders.termQuery("ip", ip))
                    .must(QueryBuilders.rangeQuery("time").gte(startTime).lte(endTime))
            );
        }

        // 3. 时间类型
        DateHistogramInterval d = DateHistogramInterval.HOUR;
        String format = "HH:mm";
        // 3. 时间类型
        switch (time_type) {
            case "hour":
                // 设置间隔时间
                d = DateHistogramInterval.HOUR;
                if ((endTime - startTime) > 1000 * 60 * 60 * 24) {
                    format = "MM-dd HH:mm";
                } else {
                    format = "HH:mm";
                }
                break;
            case "day":
                d = DateHistogramInterval.DAY;
                format = "MM-dd";
                break;
            case "month":
                d = DateHistogramInterval.MONTH;
                format = "yyyy-MM";
                break;
            case "15m":
                d = DateHistogramInterval.minutes(15);
                format = "HH:mm";
                break;
            default:
                return null;
        }
        // 4. 设置聚合条件
        prepareSearch.addAggregation(
                getDateHistogramAggregationBuilder(d, format, startTime, endTime, fileds, value_type)
        );
        logger.info("添加时间聚合查询 -----> " + prepareSearch.toString());
        // 5. 获取结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        // 6. 解析结果
        InternalDateHistogram internalDateHistogram = searchResponse.getAggregations().get("data_time");

        List<InternalDateHistogram.Bucket> buckets = internalDateHistogram.getBuckets();
        return buckets;
    }

    /**
     * 获取 聚合规则
     *
     * @param d
     * @param format
     * @param start_time 开始时间
     * @param end_time   结束时间
     * @param field      字段
     * @param value_type 要求的聚合规则 "min"/"max"/"sum"/"difference"/"avg"
     * @return
     */
    private static DateHistogramAggregationBuilder getDateHistogramAggregationBuilder(
            DateHistogramInterval d, String format, Long start_time, Long end_time, String field, String value_type) {
//        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 1. 通用时间桶
        DateHistogramAggregationBuilder dateHistogramAggregation =
                AggregationBuilders.dateHistogram("data_time")
                        .field("date_time")
                        // 设置时间桶的间隔
                        .dateHistogramInterval(d)
                        // 格式化时间 "HH:mm"
                        .format(format)
                        // 设置东八区
                        .timeZone(DateTimeZone.forID("+08:00"))
                        // 最小显示的doc_count为0
                        .minDocCount(0)
                        // 返回这段时间里面的桶
                        .extendedBounds(new ExtendedBounds(start_time, end_time));
        // 2. 如果不需要取数就直接返回
        if (StringUtils.isBlank(value_type)) {
            return dateHistogramAggregation;
        }
        // 3. 需要的话就加上取值的东西
        switch (value_type) {
            case "min":
                dateHistogramAggregation.subAggregation(AggregationBuilders.min("min_value").field(field));
                break;
            case "max":
                dateHistogramAggregation.subAggregation(AggregationBuilders.max("max_value").field(field));
                break;
            case "sum":
                dateHistogramAggregation.subAggregation(AggregationBuilders.sum("sum_value").field(field));
                break;
            case "difference":
                dateHistogramAggregation.subAggregation(AggregationBuilders.min("min_value").field(field));
                dateHistogramAggregation.subAggregation(AggregationBuilders.max("max_value").field(field));
                break;
            case "avg":
                dateHistogramAggregation.subAggregation(AggregationBuilders.avg("avg_value").field(field));
                break;
            default:
                return null;
        }
        return dateHistogramAggregation;
    }

//    --------------------------------------------------------- 去 重 查 询 ---------------------------------------------------------

    /**
     * 实时数据 -> 模组监控
     *
     * @param groupList     设备list
     * @param ip            项目ip
     * @param parameterInfo 配置list
     * @param startTime     开始时间
     * @return
     */
    public static List<JSONObject> monitorGroupList(List<EquipmentManage> groupList,
                                                    String ip, ParameterInfo parameterInfo, Long startTime, List<JSONObject> jsonObjects) {
        List<JSONObject> result = new ArrayList<>();
        // 1. 获取macid集合
        Set<String> fields = new HashSet<>();
        groupList.forEach(equipmentManage -> {
            if (StringUtils.isNotBlank(equipmentManage.getCode())) {
                fields.add(equipmentManage.getCode());
            }
        });
        // 2. 准备查询语句
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 3. 设置过滤条件
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("macid", fields))
                .must(QueryBuilders.termQuery("ip", ip))
                .must(QueryBuilders.rangeQuery("time").gte(startTime))
        );
        // 4. 添加去重
        prepareSearch.setCollapse(new CollapseBuilder("macid.keyword"));
        logger.info("monitorGroupList -------> " + prepareSearch.toString());
        // 5. 获取返回值
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit[] hits = searchResponse.getHits().getHits();
        if (hits.length < 1) {
            return result;
        }
        // 6. 解析
        for (SearchHit hit : hits) {
            Map map = hit.getSourceAsMap();
            String code = map.get("macid").toString();
            JSONObject jsonObject = null;
            for (JSONObject e : jsonObjects) {
                if (code.equals(e.get("code"))) {
                    jsonObject = e;
                    break;
                }
            }
            if (jsonObject == null) {
                jsonObject = new JSONObject();
            }
            //将配置参数逐个取出作对比
            if (parameterInfo != null) {
                if (parameterInfo.getObjType().toString().equals("1")) {
                    jsonObject.put("voltage", map.get(parameterInfo.getEsName()));
                } else if (parameterInfo.getObjType().toString().equals("2")) {
                    jsonObject.put("soc", map.get(parameterInfo.getEsName()));
                } else if (parameterInfo.getObjType().toString().equals("3")) {
                    jsonObject.put("flow", map.get(parameterInfo.getEsName()));
                } else if (parameterInfo.getObjType().toString().equals("4")) {
                    jsonObject.put("temperature", map.get(parameterInfo.getEsName()));
                } else if (parameterInfo.getObjType().toString().equals("5")) {
                    jsonObject.put("soc", map.get(parameterInfo.getEsName()));
                } else if (parameterInfo.getObjType().toString().equals("6")) {
                    jsonObject.put("other", map.get(parameterInfo.getEsName()));
                }
            } else {
                break;
            }
            for (EquipmentManage equipmentManage : groupList) {
                if (code.equals(equipmentManage.getCode())) {
                    jsonObject.put("name", equipmentManage.getName());
                    jsonObject.put("code", equipmentManage.getCode());
                    result.add(jsonObject);
                    break;
                }
            }
        }
        return result;
    }

//    --------------------------------------------------------- 需 要 调 用 的 接 口 ---------------------------------------------------------

    /**
     * 获取 给出时间之后的 在设备里的 包含给出字段名的 数据
     *
     * @param time 开始的时间的毫秒数
     * @return 所有设备 含有 查询字段 的 数据
     */
    public static SearchHit[] getAlarmHits(String macid, Long time) {

        //  准备查询语句
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        prepareSearch.setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termsQuery("macid", macid))
                        .must(QueryBuilders.rangeQuery("time").gte(time))
        ).setSize(1000).addSort("date_time", SortOrder.ASC);
        logger.info("getAlarmHits -------> " + prepareSearch.toString());
        // 3. 获取结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        return searchHits;
    }


    @PreDestroy
    public void destory() {
        transportClient.close();
    }

    /**
     * 接口2查询es数据
     *
     * @param list
     * @param equipmentManage
     * @param startTime
     * @param endTime
     */
    public static SearchHit[] getDataPython2Value(List<ParameterInfo> list, EquipmentManage
            equipmentManage, Long startTime, Long endTime) {
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 1. 查询用的API
        prepareSearch.setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", equipmentManage.getCode()))
                        .must(QueryBuilders.rangeQuery("time").gte(startTime).lt(endTime))
        ).addSort(SortBuilders.fieldSort("time").order(SortOrder.DESC));

        logger.info(prepareSearch.toString());
        // 4. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        return searchResponse.getHits().getHits();
    }

    /**
     * 接口5查询es数据
     *
     * @param list
     * @param equipmentManage
     */
    public static SearchHit[] getDataPython5Value(List<ParameterInfo> list, EquipmentManage
            equipmentManage, Long time) {
        SearchRequestBuilder prepareSearch = client.prepareSearch();
        // 1. 查询用的API
        prepareSearch.setQuery(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", equipmentManage.getCode()))
                        .must(QueryBuilders.rangeQuery("time").lte(time))
        );

        logger.info(prepareSearch.toString());
        prepareSearch.setCollapse(new CollapseBuilder("macid.keyword")).addSort(SortBuilders.fieldSort("time"));
        logger.info("getNowValue -------> " + prepareSearch.toString());
        // 3. 获取查询结果
        SearchResponse searchResponse = prepareSearch.execute().actionGet();

        return searchResponse.getHits().getHits();
    }

    /**
     * 这里获取的实时状态下的电池模组的(电压,最高单体电压,最低单体单体电压,模组电压极差,电流)
     *
     * @param codes
     * @param list
     * @param equipmentManage
     * @return
     */
    public static List<ParameterInfo> getNowGroupValue
    (List<String> codes, List<ParameterInfo> list, EquipmentManage equipmentManage) throws ParseException {
        //获取 macid
        String falg = codes.get(0);
        String macid = falg.substring(0, falg.indexOf("#"));
        //获取当前日期用于拼接index
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formatData = simpleDateFormat.format(date);
        //获取当前时间,范围查询需要
        String startTime = df.format(date);
        long sT = df.parse(startTime).getTime();

        //创建查询
        SearchRequestBuilder prepareSearch = client.prepareSearch("mdbs-" + formatData)
                .setSize(1000)
                .setQuery(QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("ip", equipmentManage.getProject().getIp()))
                        .must(QueryBuilders.termQuery("macid", macid))
                        .must(QueryBuilders.rangeQuery("time").gte(sT - 60000).lt(sT))
                );
        logger.info("电池模组实时信息数据:" + prepareSearch.toString());

        //获取查询的数据
        SearchResponse searchResponse = prepareSearch.execute().actionGet();
        SearchHit[] hits = searchResponse.getHits().getHits();
        //定义map存放全部数据
        Map<String, Object> map = new HashMap<>();
        if (hits.length < 1) {
            list.forEach(parameterInfo -> {
                parameterInfo.setValue(null);
            });
            return list;
        } else {
            for (SearchHit searchHit : hits) {
                map.putAll(searchHit.getSourceAsMap());
            }
        }
        AtomicReference<Double> s = new AtomicReference<>(0.00D);
        // 存放获取的值
        List<Double> d = new ArrayList<>();
        Double o;
        // 通过比较获取相应的值
        for (int i = 0; i < codes.size(); i++) {
            String battery = codes.get(i).substring(codes.get(i).indexOf("#") + 1, codes.get(i).length()) + "Volt";

            o = Double.parseDouble(map.get(battery).toString());

            if (o == null) {
                s.set(s.get() + 0.00D);
            } else {
                d.add(o);
                double v = o;
                s.updateAndGet(v1 -> v1 + v);
            }
        }
        for (ParameterInfo pInfo : list) {
            //模组电压
            if (pInfo.getEsName().equals("mzdy")) {
                Double value = s.get();
                pInfo.setValue(value * 0.001D);
            }
            if (pInfo.getEsName().equals("mzzgdtdy")) {
                Double max = Collections.max(d);
                pInfo.setValue(max);
            }
            if (pInfo.getEsName().equals("mzzddtdy")) {
                Double min = Collections.min(d);
                pInfo.setValue(min);
            }
            if (pInfo.getEsName().equals("mzdyjc")) {
                Double max = Collections.max(d);
                Double min = Collections.min(d);
                pInfo.setValue(max - min);
            }
            if (pInfo.getEsName().equals("BatCurrent")) {
                o = Double.parseDouble(map.get("BatCurrent").toString());
                if (o == null) {
                    pInfo.setValue(null);
                } else {
                    pInfo.setValue(o);
                }
            }
        }
        return list;
    }

    /**
     * 获取TOP3 和 BOTTOM3的电压数据
     *
     * @param codes 电池模组下的所有电池单体
     * @param ip    项目的ip
     */
    public static List getGroupTopAndBottom(List<String> codes, String ip, int size) {

        // 1. 获取时间，因为需要实时
        Long time = System.currentTimeMillis() - 60000;
        // 2. 获取结果
        SearchResponse searchResponse = getSearchGroupResponse(codes, ip, time);

        //  将esName 过滤
        List<String> batteryCodes = new ArrayList<>();
        for (int i = 0; i < codes.size(); i++) {
            String code = codes.get(i).substring(codes.get(i).indexOf("#") + 1, codes.get(i).length());
            batteryCodes.add(code + "Volt");
        }
        // 3. 解析结果
        List list = new ArrayList();
        JSONObject jsonObject;

        SearchHit[] hits = searchResponse.getHits().getHits();

        //定义map存放全部数据
        Map<String, Object> map = new HashMap<>();
        if (hits.length < 1) {
            return list;
        } else {
            for (SearchHit searchHit : hits) {
                map.putAll(searchHit.getSourceAsMap());
            }
        }
        Map<String, Double> newData = new TreeMap<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            for (int k = 0; k < batteryCodes.size(); k++) {
                String code = batteryCodes.get(k);
                if (entry.getKey().equals(code)) {
                    newData.put(code, Double.parseDouble(entry.getValue().toString()) * 0.001D);
                }
            }
        }


        //排序（降序）
        Comparator<Map.Entry<String, Double>> comparator = (o1, o2) -> -(o1.getValue()).compareTo(o2.getValue());
        //排序 (升序)
        Comparator<Map.Entry<String, Double>> valueComparator = Comparator.comparingDouble(Map.Entry::getValue);
        // map转换成list进行排序
        List<Map.Entry<String, Double>> listt = new ArrayList<>(newData.entrySet());
        List<Map.Entry<String, Double>> lists = new ArrayList<>(newData.entrySet());


        // 排序
        Collections.sort(listt, comparator);
        Collections.sort(lists, valueComparator);

        for (int i = 0; i < size; i++) {
            jsonObject = new JSONObject();

            if (listt.size() > i || listt.size() == 3) {
                Map.Entry<String, Double> stringDoubleEntry = listt.get(i);
                jsonObject.put("top_value", stringDoubleEntry.getValue());
                jsonObject.put("top_name", stringDoubleEntry.getKey());

            } else {
                jsonObject.put("top_value", 0.0D);
                jsonObject.put("top_name", "未知");
            }

            if (lists.size() > i || lists.size() == 3) {
                Map.Entry<String, Double> stringDoubleEntry1 = lists.get(i);
                jsonObject.put("bottom_value", stringDoubleEntry1.getValue());
                jsonObject.put("bottom_name", stringDoubleEntry1.getKey());

            } else {
                jsonObject.put("bottom_value", 0.0D);
                jsonObject.put("bottom_name", "未知");
            }

            list.add(jsonObject);
        }
        return list;
    }

    /**
     * 获取电池模组下的所有的电池单体
     *
     * @param codes
     * @param ip
     * @param time
     * @return
     */
    private static SearchResponse getSearchGroupResponse(List<String> codes, String ip, Long time) {
        //获取 macid
        String falg = codes.get(0);
        String macid = falg.substring(0, falg.indexOf("#"));
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd");
        String formatData = simpleDateFormat.format(date);
        //  准备查询语句
        SearchRequestBuilder prepareSearch = client.prepareSearch("mdbs-" + formatData);

        //  设置过滤条件
        prepareSearch.setQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("macid", macid))
                .must(QueryBuilders.termQuery("ip", ip))
                .must(QueryBuilders.rangeQuery("time").gte(time))
        )
                .addSort(SortBuilders.fieldSort("time").order(SortOrder.DESC));
        logger.info("电池模组top3/bottom3电池单体电压 -----> " + prepareSearch.toString());
        // 5. 获取结果
        SearchResponse searchResponseData = prepareSearch.execute().actionGet();
        return searchResponseData;

    }

    /**
     * 每15分钟查找电池单体
     */
    public static ArrayList<SearchHit[]> getBattery(ArrayList<String> ips, long lastDate, long nowDate) {
        ArrayList<SearchHit[]> hitLists = new ArrayList<>();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd");
        String formatData = simpleDateFormat.format(date);
        //  准备查询语句
        SearchRequestBuilder searchRequestBuilder = client.prepareSearch("mdbs-" + formatData);
        for (int i = 0; i < ips.size(); i++) {
            searchRequestBuilder.setSize(10000).addSort("time", SortOrder.ASC)
                    .setQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("ip", ips.get(i)))
                            .must(QueryBuilders.rangeQuery("time").gte(lastDate).lte(nowDate)))
                    .setScroll(TimeValue.timeValueMinutes(8));
            //获得首次的查询结果
            SearchResponse scrollResp = searchRequestBuilder.get();
            //打印命中数量
            logger.info("游标id：" + scrollResp.getScrollId());
            logger.info("命中总数量：" + scrollResp.getHits().getTotalHits());
            logger.info("总数量：" + scrollResp.getHits().getHits().length);

            logger.info("15分钟范围  ---------------> " + searchRequestBuilder);
            SearchResponse searchResponseData = searchRequestBuilder.execute().actionGet();
            hitLists.add(searchResponseData.getHits().getHits());
        }
        return hitLists;
    }

    /**
     * 报警过程详情查询
     * @param macid
     * @param startTime
     * @param endTime
     * @return
     */
    public static SearchHit[] getBatterys(String macid, Date startTime, Date endTime) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd");
        String formatData = simpleDateFormat.format(startTime);
        //  准备查询语句
        SearchRequestBuilder searchRequestBuilder = client.prepareSearch("mdbs-" + formatData);
        searchRequestBuilder.setSize(1000).setQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("macid", macid))
                .must(QueryBuilders.rangeQuery("time").gte(startTime.getTime()).lte(endTime.getTime())));
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();

        SearchHit[] hits = searchResponse.getHits().getHits();

        return hits;
    }
}
